package com.chunlei.complete.client;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.function.BiFunction;

/**
 * learn from https://www.javadoop.com/post/completable-future
 *
 * @Author: 朝花不迟暮
 * @Description:
 * @Date: 2022/1/26
 */
public class CompletableFutureClient2 {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        //前面 3 行代码演示的是，任务 A 无返回值，所以对应的，第 2 行和第 3 行代码中，resultA 其实是 null。
        CompletableFuture.runAsync(() -> {
        }).thenRun(() -> {
        });
        CompletableFuture.runAsync(() -> {
        }).thenAccept(resultA -> {
        });
        CompletableFuture.runAsync(() -> {
        }).thenApply(resultA -> "resultB");

        //第 4 行用的是 thenRun(Runnable runnable)，任务 A 执行完执行 B，并且 B 不需要 A 的结果
        CompletableFuture.supplyAsync(() -> "resultA").thenRun(() -> {
        });
        //第 5 行用的是 thenAccept(Consumer action)，任务 A 执行完执行 B，B 需要 A 的结果，但是任务 B 不返回值。
        CompletableFuture.supplyAsync(() -> "resultA").thenAccept(resultA -> {
        });
        // 第 6 行用的是 thenApply(Function fn)，任务 A 执行完执行 B，B 需要 A 的结果，同时任务 B 有返回值。
        CompletableFuture.supplyAsync(() -> "resultA").thenApply(resultA -> resultA + " resultB");

        // showException();
        // showException1();
        // getTwoFutureResult();
        getMoreFutureResult();
    }

    /**
     * 异常处理
     *
     * @Author: 朝花不迟暮
     * @Description:
     * @Date: 2022/1/26
     */
    public static void showException() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            throw new RuntimeException();
        })
                .exceptionally(ex -> "errorResultA")
                .thenApply(resultA -> resultA + " resultB")
                .thenApply(resultB -> resultB + " resultC")
                .thenApply(resultC -> resultC + " resultD");

        System.out.println(future.join());
    }

    public static void showException1() {
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "resultA")
                .thenApply(resultA -> resultA + " resultB")
                // 任务 C 抛出异常
                .thenApply(resultB -> {
                    throw new RuntimeException();
                })
                // 处理任务 C 的返回值或异常
                .handle((re, throwable) -> {
                    if (throwable != null) {
                        return "errorResultC";
                    }
                    return re;
                })
                .thenApply(resultC -> resultC + " resultD");

        System.out.println(future.join());
    }

    /**
     * 取两个任务的结果
     *
     * @Author: 朝花不迟暮
     * @Description:
     * @Date: 2022/1/26
     */
    public static void getTwoFutureResult() {
        CompletableFuture<String> cfA = CompletableFuture.supplyAsync(() -> "resultA");
        CompletableFuture<String> cfB = CompletableFuture.supplyAsync(() -> "resultB");

        cfA.thenAcceptBoth(cfB, (resultA, resultB) -> {
        });
        cfA.thenCombine(cfB, (resultA, resultB) -> "result A + B");
        cfA.runAfterBoth(cfB, () -> {
        });
    }

    /**
     * 取多个任务的结果,获取其中一个任务
     *
     * @Author: 朝花不迟暮
     * @Description:
     * @Date: 2022/1/26
     */
    public static void getMoreFutureResult() {
        CompletableFuture cfA = CompletableFuture.supplyAsync(() -> "resultA");
        CompletableFuture cfB = CompletableFuture.supplyAsync(() -> 123);
        CompletableFuture cfC = CompletableFuture.supplyAsync(() -> "resultC");

        CompletableFuture<Void> future = CompletableFuture.allOf(cfA, cfB, cfC);
        // 所以这里的 join() 将阻塞，直到所有的任务执行结束
        future.join();

        CompletableFuture<Object> future1 = CompletableFuture.anyOf(cfA, cfB, cfC);
        Object join = future1.join();
        System.out.println(join.toString());
    }
}
